package c.c.d.s.s.o.c.as.configuration.support.token.granter;

import c.c.d.s.s.o.c.as.context.OAuth2AuthenticationHolder;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

/**
 * Description: 自定义的 {@link AuthorizationCodeTokenGranter}
 *
 * @author LiKe
 * @version 1.0.0
 * @date 2020-08-09 17:25
 */
public class CustomAuthorizationCodeTokenGranter extends AuthorizationCodeTokenGranter {

    public CustomAuthorizationCodeTokenGranter(AuthorizationServerTokenServices tokenServices, AuthorizationCodeServices authorizationCodeServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        super(tokenServices, authorizationCodeServices, clientDetailsService, requestFactory);
    }

    /**
     * Description: 覆盖 {@link AuthorizationCodeTokenGranter#getOAuth2Authentication(ClientDetails, TokenRequest)} 逻辑.<br>
     * 将认证对象 ({@link OAuth2Authentication}) 与安全框架的安全逻辑 ({@link org.springframework.security.core.context.SecurityContextHolder}) 无关的上下文绑定 ({@link OAuth2AuthenticationHolder}), 供后续使用.
     * Details: 被 {@link org.springframework.security.oauth2.provider.token.AbstractTokenGranter#grant(String, TokenRequest)} 调用.<br>
     * 与线程绑定的 {@link OAuth2Authentication} 会用于 csrf 保护机制判断逻辑的依据之一 (ref: {@link c.c.d.s.s.o.c.as.configuration.csrf.TokenEndpointCsrfStrategyAspect}).
     *
     * @param client       {@link ClientDetails} 的自定义实现: {@link c.c.d.s.s.o.c.as.configuration.support.client.CustomClientDetails}
     * @param tokenRequest {@link TokenRequest}
     * @return org.springframework.security.oauth2.provider.OAuth2Authentication
     * @author LiKe
     * @date 2020-08-09 17:31:39
     * @see AuthorizationCodeTokenGranter#getOAuth2Authentication(ClientDetails, TokenRequest)
     * @see OAuth2AuthenticationHolder
     * @see c.c.d.s.s.o.c.as.configuration.csrf.TokenEndpointCsrfStrategyAspect
     */
    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        final OAuth2Authentication oAuth2Authentication = super.getOAuth2Authentication(client, tokenRequest);

        // ~ 将认证对象与线程绑定
        OAuth2AuthenticationHolder.set(oAuth2Authentication);
        return oAuth2Authentication;
    }
}
